package task

import (
	"container/heap"
	"context"
	"encoding/json"
	"log/slog"
	"sync"
	"time"

	"github.com/robfig/cron/v3"

	"torler.com/qingyue/apps/spider/internal/core"
	"torler.com/qingyue/common/types"
	"torler.com/qingyue/pkg/tools"
)

const (
	// 默认最大并发数
	MAX_CONCURRENCY = 5
	// 调度器间隔
	SCHEDULER_INTERVAL = 5 * time.Second
)

/*
*
* 任务管理器
* 1.实现对Task的基本操作
* 2.实现根据Task的runmode 和corn 启动或定时启动任务
* 3.支持并发限制、优先级调度和任务去重
 */
type TaskManager struct {
	name           string
	appCtx         *core.AppContext        // 上下文,用于存放三方组件
	tasks          []*Task                 // 所有任务定义
	cron           *cron.Cron              // 定时任务触发器
	mu             sync.RWMutex            // 读写锁保护并发访问
	running        map[types.TaskName]bool // 记录正在运行的任务
	logger         *slog.Logger
	runnerProvider func(name types.RunnerName) Runner

	// 新增字段用于任务调度控制
	maxConcurrency int                     // 最大并发数
	currentRunning int                     // 当前运行任务数
	waitingTasks   *PriorityTaskQueue      //等待执行的任务队列
	taskCond       *sync.Cond              // 条件变量用于任务调度
	taskEntryIDs   map[string]cron.EntryID // 保存定时任务EntryID，用于删除任务

}

func NewTaskManager(appCtx *core.AppContext) *TaskManager {
	taskQueue := &PriorityTaskQueue{}
	heap.Init(taskQueue)
	appCtx.DB.AutoMigrate(&TaskRunInfo{}, &TaskInfo{})

	mgr := &TaskManager{
		name:           "任务管理器",
		tasks:          make([]*Task, 0),
		cron:           cron.New(),
		running:        make(map[types.TaskName]bool),
		appCtx:         appCtx,
		logger:         appCtx.Logger.WithGroup("taskMgr"),
		maxConcurrency: MAX_CONCURRENCY,
		waitingTasks:   taskQueue,
		taskEntryIDs:   make(map[string]cron.EntryID),
	}

	mgr.taskCond = sync.NewCond(&mgr.mu)
	return mgr
}

func (it *TaskManager) Name() string {
	return it.name
}

// AddTask 添加任务
//
// 一次性任务：则直接添加到队列中
// 定时任务：则添加到定时任务中
func (it *TaskManager) AddTask(tsk *Task) error {
	it.mu.Lock()
	defer it.mu.Unlock()
	defer tsk.saveTaskInfo()

	tsk.saveTaskInfo()
	// 设置任务管理器
	tsk.mgr = it
	logger := it.logger.With("task_id", tsk.id, "task_name", tsk.name, "task_run_mode", tsk.runMode, "task_corn", tsk.corn)

	// 添加到任务列表
	it.tasks = append(it.tasks, tsk)

	// //一次性任务
	if tsk.runMode == types.RunOnce {
		it.addTaskForOnce(tsk)

		//定时任务
	} else if tsk.runMode == types.RunCorn && tsk.corn != "" {
		it.addTaskForCorn(tsk)
	}

	tsk.sched = true
	logger.Info("任务已添加")
	return nil
}
func (it *TaskManager) addTaskForOnce(tsk *Task) error {
	if tsk.mgr == nil {
		tsk.mgr = it
	}
	heap.Push(it.waitingTasks, &PriorityTask{Task: tsk, Priority: tsk.priority})
	it.taskCond.Signal()
	return nil
}
func (it *TaskManager) addTaskForCorn(tsk *Task) error {
	//立即执行一次
	if tsk.runOnceWhenAdded {
		it.addTaskForOnce(tsk.copyForCornRunTask())
	}
	// 添加定时任务
	entryID, err := it.cron.AddFunc(string(tsk.corn), func() {
		it.mu.Lock()
		// 为定时任务创建运行任务
		runTask := tsk.copyForCornRunTask()
		it.addTaskForOnce(runTask)
		it.mu.Unlock()
	})

	it.taskEntryIDs[tsk.id] = entryID
	return err
}

// RemoveTask 删除任务
//
// 删除任务：若是定时任务，则删除定时任务；若是一次性任务，则删除队列中的任务
func (it *TaskManager) RemoveTask(id string) error {
	it.mu.Lock()
	defer it.mu.Unlock()

	for i, task := range it.tasks {

		if task.id == id {
			logger := it.logger.With("task_id", task.id).With("task_name", task.name)
			// 从任务列表中移除
			it.tasks = append(it.tasks[:i], it.tasks[i+1:]...)

			// 如果是定时任务，也需要从cron中移除
			if task.runMode == types.RunCorn {
				if entryID, exists := it.taskEntryIDs[id]; exists {
					it.cron.Remove(entryID)
					delete(it.taskEntryIDs, id)
					logger.Info("成功移除定时器")
				}
			}

			logger.Info("任务已删除")
			return nil
		}
	}

	it.logger.With("task_id", id).Warn("未找到要删除的任务")
	return nil
}

// List 获取所有任务列表
func (it *TaskManager) List() []*Task {
	it.mu.RLock()
	defer it.mu.RUnlock()

	// 返回任务列表的副本以避免外部修改
	tasks := make([]*Task, len(it.tasks))
	copy(tasks, it.tasks)
	return tasks
}

// LoadTaskWhenStart 加载任务
//
// 当启动时加载未完成的任务
func (it *TaskManager) loadTaskWhenStart() error {
	records := GetAllTaskNotFinished(it.appCtx.DB)
	it.logger.Info("加载未完成任务", slog.Int("count", len(records)))

	for _, record := range records {
		// 根据record信息重建任务
		task := it.rebuildTaskFromRecord(record)
		if task != nil {
			// 将任务添加到队列中继续执行
			it.tasks = append(it.tasks, task)

			// 只有一次性任务才重新加入队列
			if task.runMode == types.RunOnce {
				heap.Push(it.waitingTasks, &PriorityTask{Task: task, Priority: task.priority})
				it.taskCond.Signal()
			}
			it.logger.Info("已加载未完成任务", "task_name", task.name)
		}
	}

	return nil
}

// rebuildTaskFromRecord 根据任务记录重建任务对象
func (it *TaskManager) rebuildTaskFromRecord(record *TaskRunInfo) *Task {
	taskInfo := GetTaskInfoByTaskId(it.appCtx.DB, record.TaskId)
	if taskInfo == nil {
		it.logger.Warn("未找到任务信息", "task_id", record.TaskId)
		return nil
	}

	task := &Task{
		ctx:        it.appCtx,
		mgr:        it,
		id:         taskInfo.TaskId,
		name:       taskInfo.TaskName,
		single:     taskInfo.Single,
		runMode:    taskInfo.RunMode,
		corn:       taskInfo.Corn,
		priority:   taskInfo.Priority,
		RunnerName: taskInfo.RunnerName,
		params:     make(map[string]any),
		result:     make(map[string]any), // 初始化结果字段

		state:  record.State,
		record: record,
		info:   taskInfo,
	}

	// 解析参数
	if taskInfo.Params != "" {
		err := json.Unmarshal([]byte(taskInfo.Params), &task.params)
		if err != nil {
			it.logger.Error("解析任务参数失败", "task_name", task.name, "error", err)
		}
	}
	// 解析结果
	if record.Result != "" {
		err := json.Unmarshal([]byte(record.Result), &task.result)
		if err != nil {
			it.logger.Error("解析任务结果失败", "task_name", task.name, "error", err)
		}
	}

	return task
}

func (it *TaskManager) SetRunnerCreator(creator func(name types.RunnerName) Runner) {
	it.runnerProvider = creator
}

// Start 启动管理器
func (it *TaskManager) Start(context.Context) error {
	it.logger.Info("启动任务管理器")
	// 启动任务调度器协程
	go it.taskScheduler()

	// 加载未完成的任务
	it.loadTaskWhenStart()

	// 重新获取锁以启动cron调度器
	it.mu.Lock()
	// 启动cron调度器
	it.cron.Start()
	it.mu.Unlock()
	return nil
}

// Stop 停止管理器
func (it *TaskManager) Stop(ctx context.Context) error {
	it.mu.Lock()
	defer it.mu.Unlock()

	it.logger.Info("停止任务管理器")

	// 停止cron调度器
	if it.cron != nil {
		it.cron.Stop()
	}

	// 等待所有正在运行的任务完成或超时
	done := make(chan struct{})
	go func() {
		for it.currentRunning > 0 {
			time.Sleep(100 * time.Millisecond)
		}
		close(done)
	}()

	select {
	case <-done:
		it.logger.Info("所有任务已完成")
	case <-ctx.Done():
		it.logger.Warn("停止任务管理器超时", "error", ctx.Err())
	}

	it.logger.Info("任务管理器已停止")
	return nil
}

// taskScheduler 任务调度器
//
// 任务调度器负责调度任务
// 任务调度器会根据任务配置的运行模式，执行任务
func (it *TaskManager) taskScheduler() {
	logger := it.logger.WithGroup("task_scheduler")
	logger.Info("任务调度器启动")

	for {
		it.mu.Lock()

		// 等待直到有任务可以运行且未达到最大并发数
		for (it.waitingTasks.Len() == 0 || it.currentRunning >= it.maxConcurrency) && it.cron != nil {
			it.taskCond.Wait()
		}

		// 检查是否有任务需要执行
		if it.waitingTasks.Len() > 0 && it.currentRunning < it.maxConcurrency {
			// 从优先级队列中取出优先级最高的任务
			priorityTask := heap.Pop(it.waitingTasks).(*PriorityTask)
			task := priorityTask.Task

			// 检查是否为单例任务且已在运行
			if task.single && it.running[task.name] {
				logger.Info("单例任务已在运行，跳过", "task_name", task.name)
				it.mu.Unlock()
				continue
			}

			// 标记任务为正在运行
			it.running[task.name] = true
			it.currentRunning++

			// 启动协程执行任务
			go func() {
				// 执行任务
				it.runTask(task)

				// 任务执行完成后更新状态
				it.mu.Lock()
				delete(it.running, task.name)
				it.currentRunning--
				it.taskCond.Signal() // 通知调度器可能有新的执行机会
				it.mu.Unlock()
			}()

			logger.Info("任务开始执行", "task_name", task.name, "priority", priorityTask.Priority)
		}

		it.mu.Unlock()
	}
}

// runTask 实际执行任务
func (it *TaskManager) runTask(task *Task) {
	logger := it.logger.With("task_id", task.id, "task_name", task.name).With("params", tools.ToJson(task.params))
	logger.Info("开始执行任务", "task", task.name)

	task.logger = logger
	task.state = types.TaskStatusRunning
	task.startTime = time.Now()
	task.saveTaskRecord()

	defer func() {
		task.endTime = time.Now()
		err := task.saveTaskRecord()
		if err != nil {
			logger.Error("保存任务状态失败", "err", err)
		} else {
			logger.Info("任务执行完成",
				"task", task.name,
				"state", task.state,
				"duration", task.endTime.Sub(task.startTime),
				"result", tools.ToJson(task.result),
			)
		}

	}()

	runner := it.createRunner(task.RunnerName)
	if runner == nil {
		task.state = types.TaskStatusError
		logger.Error("找不到对应的任务执行器", "name", task.RunnerName)
		return
	}
	runner.Preload(task)
	// 记录执行器开始执行
	logger.Info("任务执行器开始执行", "task", task.name, "runner", task.RunnerName)

	err := runner.Run(task)
	if err != nil {
		task.state = types.TaskStatusError
		task.SetResultError(err)
		logger.Error("任务执行失败", "task", task.name, "error", err)
		return
	}
	task.state = types.TaskStatusSuccess
}
func (it *TaskManager) createRunner(name types.RunnerName) Runner {
	return it.runnerProvider(name)
}
